home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / CUGUK / COMMS / C035.ZIP / JMODEM_E.C < prev    next >
Text File  |  1990-02-17  |  17KB  |  269 lines

  1. /****************************************************************************/
  2. /*   FILE JMODEM_E.C                                                        */
  3. /*   Created 11-JAN-1990                 Richard B. Johnson                 */
  4. /*                                       405 Broughton Drive                */
  5. /*                                       Beverly, Massachusetts 01915       */
  6. /*                                       BBS (508) 922-3166                 */
  7. /*   open_chan();                                                           */
  8. /*   close_chan();                                                          */
  9. /*   read_chan();                                                           */
  10. /*   write_chan();                                                          */
  11. /*                      Communications I/O procedures                       */
  12. /*   These procedures will have to be replaced for JMODEM to execute on     */
  13. /*   a system other than a MS_DOS computer. They are VERY hardware-specific.*/
  14. /*   These procedures are grouped so that they can be replaced as a unit.   */
  15. /*   You must replace the following:                                        */
  16. /*  (1) OPEN a communications channel.                                      */
  17. /*  (2) CLOSE the opened channel.                                           */
  18. /*  (3) READ [variable] bytes from the channel.                             */
  19. /*  (4) WRITE [variable] bytes to the channel.                              */
  20. /*                                                                          */
  21. /*  When attempting to READ bytes, some sort of time-out must be provided   */
  22. /*  within the routine to prevent a "wait-forever" syndrome.                */
  23. /*                                                                          */
  24. /*  VAX/VMS, QIO routines are ideal!                                        */
  25. /*                                                                          */
  26. /****************************************************************************/
  27. #include <stdio.h>                      /* For FILE structure           */
  28. #include <conio.h>                      /* For _inp() and _outp()       */
  29. #include <dos.h>                        /* For _enable() and _disable() */
  30. #include <memory.h>                     /* _memcpy();                   */
  31. #include "jmodem.h"                     /* JMODEM defines               */
  32. #include "uart.h"                       /* 8250 UART                    */
  33. #pragma intrinsic (inp, outp, _disable, _enable, memcpy)
  34. typedef struct  {
  35.         unsigned short base;            /* Base port address            */
  36.         unsigned short mask;            /* Interrupt controller mask    */
  37.         unsigned short int_num;         /* Interrupt number             */
  38.         } PORTS;
  39.  
  40. PORTS port_pars[] =     {
  41.                         {0x3F8  ,       /* Base port address    COM1    */
  42.                         0xEF    ,       /* IRQ4 11101111B       COM1    */
  43.                         0x0C    ,       /* Interrupt number             */
  44.                         }       ,
  45.                         {
  46.                         0x2F8   ,       /* Base port address    COM2    */
  47.                         0xF7    ,       /* IRQ3 11110111B       COM2    */
  48.                         0x0B    ,       /* Interrupt number             */
  49.                         }       ,
  50.                         {
  51.                         0x3E8   ,       /* Base port address    COM3    */
  52.                         0xEF    ,       /* IRQ4 11101111B       COM3    */
  53.                         0x0C    ,       /* Interrupt number             */
  54.                         }       ,
  55.                         {
  56.                         0x2E8   ,       /* Base port address    COM4    */
  57.                         0xF7    ,       /* IRQ3 11110111B       COM4    */
  58.                         0x0B    ,       /* Interrupt number             */
  59.                         }
  60.                         };
  61. extern unsigned char *int_buffer;       /* pointer to interrupt buffer  */
  62. extern unsigned short user_abort;       /* User abort flag              */
  63. unsigned char *write_ptr;               /* Interrupt buffer             */
  64. unsigned char *read_ptr;                /* Interrupt buffer             */
  65. unsigned short port;                    /* Port number                  */
  66. unsigned short old_mask;                /* Old interrupt control mask   */
  67. unsigned short old_ier;                 /* Old interrupt enable regis   */
  68. unsigned short old_mcr;                 /* Old modem control register   */
  69. unsigned short old_stat;                /* Modem status for flow-contr  */
  70. unsigned short timer;                   /* Global timer                 */
  71. unsigned short hardware_port;           /* Physical port                */
  72. void interrupt far fatal_abort(void);   /* Abort vector                 */
  73. void interrupt far com_int(void);       /* Interrupt service routine    */
  74. void interrupt far tim_int(void);       /* Timer interrupt              */
  75. void (interrupt far *old_tim)();        /* Pointer to old timer intr.   */
  76. void (interrupt far *old_com)();        /* Pointer to old commu intr.   */
  77. void (interrupt far *old_brk)();        /* Pointer to old break key.    */
  78. /****************************************************************************/
  79. /*                 Open the communications channel                          */
  80. /*                                                                          */
  81. /*    Under MS-DOS this involves saving the com-port vector, interrupt      */
  82. /*    controller mask, and the user-tick timer vector.                      */
  83. /*    New vectors and masks and patched for the communications interrupt    */
  84. /*    service routine and the local timer. These vectors will be restored   */
  85. /*    within the CLOSE channel routine.                                     */
  86. /*                                                                          */
  87. /****************************************************************************/
  88. unsigned short open_chan (user_port)
  89. unsigned short user_port;               /* Port offset ( 0 - 3 )           */
  90. {
  91.     short i;
  92.     flush();                            /* Initialize the interrupt buffer */
  93.     hardware_port =
  94.        port_pars[user_port].base;       /* Set hardware port               */
  95.     old_ier = inp(hardware_port +IER);  /* Get interrupt enable regis      */
  96.     old_mcr = inp(hardware_port +MCR);  /* Get old modem control register  */
  97.     old_stat = inp(hardware_port+MSR)
  98.                &0xF0;                   /* Get current modem status        */
  99.     old_brk = _dos_getvect(0x1B);       /* Get old break key vector        */
  100.    _dos_setvect(0x1B,fatal_abort);      /* Set fatal abort vector (1)      */
  101.    _dos_setvect(0x23,fatal_abort);      /* Set fatal abort vector (2)      */
  102.     old_mask = inp(0x21);               /* Save old interrupt mask         */
  103.     old_tim = _dos_getvect(0x1C);       /* Get old DOS timer-tick vector   */
  104.     old_com = _dos_getvect(
  105.        port_pars[user_port].int_num);   /* Get old communications vector   */
  106.     _dos_setvect(0x1C,tim_int);         /* Set new timer interrupt         */
  107.     _dos_setvect(
  108.        port_pars[user_port].int_num,    /* Set new communications vector   */
  109.        com_int);
  110.     outp(0x21,old_mask &
  111.        port_pars[user_port].mask);      /* Set interrupt enable mask       */
  112.     outp(hardware_port+IER, IER_ERBFI); /* Enable received data available  */
  113.     outp(hardware_port+MCR, 0x0F);      /* Turn everything on.             */
  114.     for (i=0; i<8; i++)                 /* Edge-triggering, read the ports */
  115.     {
  116.         outp(0x20,0x20);                /* Reset the hardware controller   */
  117.         inp(hardware_port + i);         /* Port to clear                   */
  118.     }
  119.     outp(0x20,0x20);                    /* Reset the hardware controller   */
  120.     flush();                            /* Clear interrupt buffer again    */
  121.     return JM_NRM;
  122. }
  123. /****************************************************************************/
  124. /*                 Close the communications channel                         */
  125. /*                                                                          */
  126. /*    Under MS-DOS this involves restoring the interrupt vectors and        */
  127. /*    controller mask that was saved during the OPEN routine.               */
  128. /*                                                                          */
  129. /****************************************************************************/
  130. unsigned short close_chan (user_port)
  131. unsigned short user_port;
  132. {
  133.     outp(hardware_port+IER,old_ier);    /* Set old interrupt enable        */
  134.     outp(hardware_port+MCR,old_mcr);    /* Set old modem control           */
  135.     outp(0x21,old_mask);                /* Restore old interrupt mask      */
  136.     _dos_setvect(
  137.        port_pars[user_port].int_num,    /* Set old communications vector   */
  138.        old_com);
  139.     _dos_setvect(0x1C,old_tim);         /* Set old timer interrupt         */
  140.     _dos_setvect(0x1B,old_brk);         /* Set old break interrupt         */
  141.     return JM_NRM;
  142. }
  143. /****************************************************************************/
  144. /*              Read from the communications channel                        */
  145. /*                                                                          */
  146. /*    This involves transferring data from the interrupt buffer and         */
  147. /*    maintaining the interrupt buffer pointers. A timeout is established.  */
  148. /*                                                                          */
  149. /****************************************************************************/
  150. unsigned short read_chan (bytes, buffer)
  151. unsigned short bytes;                   /* Bytes requested                 */
  152. unsigned char *buffer;                  /* Pointer to the user's buffer    */
  153. {
  154.     unsigned short count;               /* Byte count                      */
  155.     unsigned short avail;               /* Bytes available                 */
  156.     timer = TIMOUT;                     /* Set initial timeout value       */
  157.     count = bytes;                      /* Set byte-count                  */
  158.  
  159.     while (count && timer)              /* If byte request or no timeout   */
  160.     {
  161.         avail = write_ptr - read_ptr;   /* Bytes available                 */
  162.         if (avail)                      /* If bytes available              */
  163.         {
  164.             if (avail > count)          /* If more bytes than we need      */
  165.                 avail = count;          /* Take only what we need          */
  166.             memcpy (buffer   ,          /* User's buffer                   */
  167.                     read_ptr ,          /* Interrupt buffer pointer        */
  168.                     avail)   ;          /* Copy to user's buffer           */
  169.             count -= avail;             /* Update count                    */
  170.             read_ptr +=avail;           /* Update read pointer             */
  171.             buffer   +=avail;           /* Update write pointer            */
  172.             timer = TIMOUT;             /* Set new timer value             */
  173.         }
  174.         _disable();                     /* Clear interrupts                */
  175.         if (read_ptr == write_ptr)      /* If no bytes available           */
  176.         {
  177.             read_ptr = int_buffer;      /* Initialize the interrupt buffer */
  178.             write_ptr = int_buffer;     /* Initialize the interrupt buffer */
  179.         }
  180.         _enable();                      /* Enable interrupts               */
  181.     }
  182.     return(bytes - count);              /* Actual characters received      */
  183. }
  184. /****************************************************************************/
  185. /*                      Flush the interrupt buffer                          */
  186. /****************************************************************************/
  187. void flush()
  188. {
  189.     _disable();
  190.     read_ptr = int_buffer;              /* Initialize the interrupt buffer */
  191.     write_ptr = int_buffer;             /* Initialize the interrupt buffer */
  192.     _enable();
  193. }
  194. /****************************************************************************/
  195. /*                      Communications transmit routine                     */
  196. /*    Write 'bytes' bytes from buffer to the UART. Don't return until done  */
  197. /*    unless the carrier failed or the hardware broke.                      */
  198. /****************************************************************************/
  199. unsigned short write_chan (bytes, buffer)
  200. unsigned short bytes;                         /* Bytes to send             */
  201. unsigned char *buffer;                        /* Pointer to the buffer     */
  202. {
  203.     register unsigned short status;
  204.  
  205.     timer = TIMOUT;
  206.     while ((bytes && timer) && !user_abort )  /* Bytes, no abort, no timout */
  207.     {
  208.         while ( (status = (inp(hardware_port+MSR) & 0xF0) )!= old_stat)
  209.         {                                  /* Flow control loop            */
  210.             if (!(status & MSR_RLSD))      /* If the modem carrier failed  */
  211.             {
  212.                 user_abort = 0x0FFFF;      /* Set the abort flag           */
  213.                 return JM_ABT;
  214.             }
  215.         }
  216.         status = inp(hardware_port+LSR);   /* Get line-status              */
  217.         if (status & LSR_THRE)             /* If TX holding register empty */
  218.         {
  219.             outp(hardware_port,*buffer++); /* Send the byte                */
  220.             bytes--;                       /* Bump the byte-count          */
  221.             timer = TIMOUT;                /* Set new timer-value          */
  222.         }
  223.     }
  224.     return JM_NRM;
  225. }
  226. /****************************************************************************/
  227. /*                Communications adapter hardware interrupt                 */
  228. /*    This is very simple because we interrupt on receive only. Since we    */
  229. /*    must wait until the entire block has been received and checked be-    */
  230. /*    for doing anything else, the transmitter is polled.                   */
  231. /*                                                                          */
  232. /****************************************************************************/
  233. void interrupt far com_int()
  234. {
  235.     *write_ptr = (unsigned char)
  236.         inp(hardware_port);                    /* Put byte in buffer        */
  237.     outp(0x20,0x20);                           /* Reset hardware controller */
  238.     if (write_ptr < int_buffer + DAT_LEN )     /* Check buffer for overflow */
  239.         write_ptr++;                           /* Bump pointer if room      */
  240. }
  241. /****************************************************************************/
  242. /*                            Timer interrupt                               */
  243. /*    A WORD (timer) gets decremented every timer-tick if it is not already */
  244. /*    zero. This is used to set time-out values in the communication pro-   */
  245. /*    cedures so that a "wait-forever" can't occur.                         */
  246. /*                                                                          */
  247. /****************************************************************************/
  248. void interrupt far tim_int()
  249. {
  250.     if (timer)                          /* If NZ                           */
  251.         timer--;                        /* Bump the timer                  */
  252.     outp(0x20,0x20);                    /* Reset the hardware controller   */
  253.     _enable();                          /* Allow network interrupts        */
  254.     _chain_intr(old_tim);               /* Go to old timer-tick routine    */
  255. }
  256. /****************************************************************************/
  257. /*                          A B O R T   trap                                */
  258. /*    Control-C and control-break vectors are set to point here so that     */
  259. /*    a user-break harmlessly sets a flag so that interrupt vectors may     */
  260. /*    properly restored upon program exit.                                  */
  261. /*                                                                          */
  262. /****************************************************************************/
  263. void interrupt far fatal_abort()
  264. {
  265.     user_abort = 0xFFFF;                              /* Set abort flag     */
  266. }
  267. /****************************************************************************/
  268. /******************** E N D   O F   M O D U L E *****************************/
  269.